Structured financial reporting is latest and greatest method of exchanging financial data and reports. The use of XBRL is expanding allover the world, and it is becoming the standard method for exchanging structured financial reports.

The objective of this document is to provide the reader with a basic understanding of what XBRL is, what it does, and how it is implemented.

Parts of this material depends heavily, and refers to the XBRL Taxonomy Development Handbook published by XBRL US and publicly available on the their website. As mentioned in the preface of the handbook, it was created as a guide for creating XBRL taxonomies based on XBRL US experience, which makes it a very valuable resource for anyone or organization interested in implementation of XBRL.

1 Outcomes

This material should provide:

  • Basic understanding of XBRL and its components
  • Familiarity with core terminology and what it refers to
  • Basic understanding of Taxonomy and instance document
  • Basic understanding of the process of development of an XBRL taxonomy and structured reporting process
  • Understanding the ecosystem of structured financial reporting and the supporting technologies

2 Back in time

To explain the most basic concept of XBRL we need to take a trip back in time, to the ancient Egyptian writings.

Cartouche
[Image by Osama Shukir Muhammed Amin FRCP(Glasg), CC BY-SA 4.0 https://creativecommons.org/licenses/by-sa/4.0, via Wikimedia Commons]

In the image above, some writing is encapsulated in an oval shape called “Cartouche”, according to the common understanding, this means that the encapsulated writing represents a royal name. The ancient Egyptians choose this method to draw the attention to the information by marking or “tagging” this important information by the oval shape.

XBRL does the same thing, it is tagging important financial information included in a report, in the case of XBRL, this tagging has consequences when the information is processed by a computer.

3 Why XBRL and what is it exactly?

XBRL stands for eXtensible Business Reporting Language, and it is usually described in terms of what it does, in brief, XBRL provides standards for storing and electronic communication of financial information enabling efficient processing, storage, retrieval, analysis and comparison of the information.

The increase in size of data and regulatory requirements derives the need for more efficient and structured methods to handle all this data and make convert it into a resource rather than a burden.

3.1 Who uses XBRL?

The XBRL Taxonomy Development Handbook in page 6 lists successful implementation of XBRL around the worlds, that includes:

  • United States: Stock exchange commission (SEC), and Financial Depository Insurance Corporation (FDIC) with total reporting entities of over 17,500

  • United Kingdom: Her Majesty’s Revenues & Customs (HMRC), and Companies House with reporting entities of over 2 million

  • Spain: Business Registrar, Banking Regulator, Securities Regulation, Accounting Oversight and State Federal Comptroller with reporting entities of over 800,000

  • Others: Europe (European Single Electronic Format ESEF), India, Singapore, South Korea, Italy, Peru, World bank and many others

  • Governments and government agencies allover the world are using XBRL, countries like Netherlands and Australia implemented Standard Business Reporting (SBR) programs which are programs designed to reduce regulatory burden for businesses and relies heavily on XBRL.

Currently XBRL international website lists more than 20 XBRL jurisdictions (a jurisdiction is a local representative for XBRL acting as the primary liaison to national government, technology firms and business communities)

3.2 How do we collect financial data

The methods and processes of financial data collection evolved over time, we started with paper based submissions, then computer discs, then electronic submissions through web based portals. XBRL is the next new thing in this evolution, and it adds value in a lot of ways such as:

  • It provides for a stable structure of the data content
  • It separates data content from the form of the submission
  • Provide for automation, which increases accuracy, cost and time savings

And many more benefits relating to the quality and richness of that data that we will look into later.

3.3 Current issues that XBRL addresses

As mentioned, XBRL provides for structured contextually rich machine readable data, which allows for automation, and that address most of the main data issues in general, for regulators and for issuers.

General Issues:

  • Machine Readable: reports with XBRL tagging can be consumed and analyzed by computers through XBRL enabled software (XBRL Processors) as opposed to paper based or unstructured reports.
  • Interoperability: XBRL is self-describing and uses XML syntax which makes the information in XBRL system independent, in other words, the same XBRL information package can be consumed by any system that has XBRL enabled software, which addresses compatibility issues.
  • It provides for a common set of rules that can be used in exchanging any financial information, hence it provides a common language for exchanging data, addressing comparability issues.
  • XBRL provides for automated means of compiling, transmitting, validating and analyzing financial data, which increase efficiency, time and cost saving and at the same time increasing quality of data.
  • XBRL provides high quality, contextually rich financial data rather than fragmented data.
  • XBRL is free and opensource standard, with no licensing fees, addresses issues of propitiatory standards and software, it should be noted that XBRL enabled software is not free.

Regulator Issues:

  • High volumes of data and reports: as mentioned, XBRL provides for automation in collecting and processing data, which facilitates handling high volumes in an accurate and efficient manner.
  • Review and validation: XBRL give financial report a structure that enable creation of validation rules based on regulations, business rules and any other criteria, and that in turn enables quick corrective action to be taken when needed.
  • Data can be stored for cross checking and further analysis and comparison.
  • Single source of the truth, XBRL structure allows data to be used for many purposes, for example, same report can contain data structures required for a regulator, census, taxes …

Issuer Issues:

  • Simplifies the compilation of reports required by multiple regulators from the same dataset.
  • XBRL taxonomies and the related guides issued by regulators provide for clear and unambiguous reporting requirements, and simplifies compliance.
  • Reduces the chance of costly errors.

Why XBRL? In short, it addresses most current issues relating to exchange of financial data, it is widely used allover the world, and it is simply the next step in the evolution of financial data exchange systems.

3.4 What is Extensible Business Reporting Language (XBRL)?

The Specifications
Technically XBRL is based on XML (eXtensible Markup Language), it can be said that XBRL is an XML extension optimized to deal with business information. In other words, XBRL does what it does by being based on XML.

XBRL is a set of specifications developed and maintained by XBRL International. The base XBRL specification (now version 2.1) is stable since 2003, with additional specifications being added to augment it such as XBRL Dimensions.

XBRL specification are freely available without licensing, note that this doesn’t apply for XBRL enabled software which might have licensing fees.

Data Model
XBRL specifications are tools that enables the definition of dictionaries, data models and rules called XBRL Taxonomies, also XBRL specifications provide the tools to create structured financial reports based on XBRL Taxonomies, these financial reports are called XBRL Instances.

So we can say that XBRL is the set of tools used to create data models and structures that are the basis for structured financial reporting.

Communication Language
The purpose of XBRL is to enable exchange of structured financial data between systems, some times the term “transport model” is used to refer to XBRL.

“A Transport Model serves as an organizational structure when moving data from a source to a consumer”

Understanding XBRL and how it does what it does, start with XML, in the next section we will go through some of XML concepts that are relevant to understanding XBRL.

3.5 XML and markup languages

Markup languages in general tags the content of a file or a document in a way that makes it machine readable, i.e. when processed by a computer, the tags tell the computer what to do with the content.

Markup languages has different purposes, for example Hyper Text Markup Language (“HTML”) tags tell the computer how to display the content, while few of the main purposes of XML is to store, organize and transport content between systems.

Markup languages are usually system independent, for example all systems have tools to read and parse XML, in other words, an XML file created in a Windows system can be read an parsed by a Linux based system.

3.6 XML Basics

As mentioned XML is a markup language, and it is a set of specifications, rules and tools for describing, storing, and transporting data between systems.

Assume that we want to encode a table of invoices into XML, a fragment of that XML might look as follows:

<table> 


  <invoice CustomerName="abc" InvoiceNum="101">589.91</invoice>


  <invoice CustomerName="xyz" InvoiceNum="101">257.42</invoice>


</table>

3.6.1 XML Form

XML document is composed of elements, each element starts with an opening tag and ends with a closing tag, there can be values or other elements within the opening and closing tags. The XML structure is in the form of a tree, having a root element containing all other elements.

<table> and </table> in the above XML fragment are the opening and closing tags of the root element called table. In the above fragment, the root element has only one child element called invoice. The invoice opening tag contains other information in the form of key, value pairs customerName="abc", invoiceNum=101, these are called attributes, which attaches more information about the element and are usually referred to using the @ symbol, as in @customerName. finally we have a value 589.91 between the invoice opening and closing tag, in this case representing the invoice amount.

To be usable, XML must be well formed XML, a well formed XML has the following:

  • All XML elements must be contained in one root element
  • Each element must have an opening and closing tag
  • Elements must be properly nested
  • Attributes must be quoted

For more about XML well formedness see W3Schools XML Tutorial

3.6.2 Storing Data in XML

Let’s assume we have a table of invoices that we need to store in XML format and send over to another computer, first let’s construct the table:

# Generate a table, same as previous test but 50 rows
set.seed(42)
# Number of rows in the table
table_rows <- 10 
# Customer names
customer_names <- c("abc", "mno","xyz")
# Data frame
tbl_1 <- data.frame(
  CustomerName = sample(customer_names, table_rows, replace = T),
  InvoiceNum = sort(sample(100:999, table_rows)),
  InvoiceDate = sort(sample(seq(as.Date('2000-01-01'), 
                                as.Date('2000-12-31'), 
                                by="day"), table_rows)
                     ),
  InvoiceCurrency = rep("CU",table_rows),
  InvoiceAmt = round(runif(table_rows, min = 100, max = 1000),2), stringsAsFactors = F)

# Display first few rows of the data.frame
head(tbl_1)

Now let’s convert that table to XML format:

# This code converts the invoices table to an XML document 
# and saves it to file

# Create XML root element
xml_root <- xml2::xml_new_root('table')

# Attach each row of the table as an <invoice> element
for(r in asplit(tbl_1,1)) {
  nd <- xml2::xml_add_child(xml_root, 'invoice')
  for(r_n in names(r)){
    xml2::xml_add_child(.x=nd, .value = r_n, r[[r_n]] )
  }
}

# Write the XML document to file
xml_out_tbl_1 <- here::here('xml_files','xml_out.xml')
invisible(xml2::write_xml(xml_root, xml_out_tbl_1))

The resulting XML file looks like this:

<?xml version="1.0" encoding="UTF-8"?>


<table>


  <invoice>


    <CustomerName>abc</CustomerName>


    <InvoiceNum>264</InvoiceNum>


    <InvoiceDate>2000-01-05</InvoiceDate>


    <InvoiceCurrency>CU</InvoiceCurrency>


    <InvoiceAmt>650.60</InvoiceAmt>


  </invoice>


  <invoice>


    <CustomerName>abc</CustomerName>


    <InvoiceNum>396</InvoiceNum>


    <InvoiceDate>2000-01-24</InvoiceDate>


    <InvoiceCurrency>CU</InvoiceCurrency>


    <InvoiceAmt>441.60</InvoiceAmt>


  </invoice>


  <invoice>


    <CustomerName>abc</CustomerName>


    <InvoiceNum>455</InvoiceNum>


    <InvoiceDate>2000-04-18</InvoiceDate>


    <InvoiceCurrency>CU</InvoiceCurrency>


    <InvoiceAmt>492.19</InvoiceAmt>


  </invoice>


  <invoice>


    <CustomerName>abc</CustomerName>


    <InvoiceNum>509</InvoiceNum>


    <InvoiceDate>2000-07-30</InvoiceDate>


    <InvoiceCurrency>CU</InvoiceCurrency>


    <InvoiceAmt>133.69</InvoiceAmt>


  </invoice>


  <invoice>


    <CustomerName>mno</CustomerName>


    <InvoiceNum>631</InvoiceNum>


    <InvoiceDate>2000-09-15</InvoiceDate>


    <InvoiceCurrency>CU</InvoiceCurrency>


    <InvoiceAmt>976.19</InvoiceAmt>


  </invoice>


  <invoice>


    <CustomerName>mno</CustomerName>


    <InvoiceNum>700</InvoiceNum>


    <InvoiceDate>2000-10-09</InvoiceDate>


    <InvoiceCurrency>CU</InvoiceCurrency>


    <InvoiceAmt>488.58</InvoiceAmt>


  </invoice>


  <invoice>


    <CustomerName>mno</CustomerName>


    <InvoiceNum>721</InvoiceNum>


    <InvoiceDate>2000-10-24</InvoiceDate>


    <InvoiceCurrency>CU</InvoiceCurrency>


    <InvoiceAmt>961.82</InvoiceAmt>


  </invoice>


  <invoice>


    <CustomerName>abc</CustomerName>


    <InvoiceNum>978</InvoiceNum>


    <InvoiceDate>2000-11-09</InvoiceDate>


    <InvoiceCurrency>CU</InvoiceCurrency>


    <InvoiceAmt>898.98</InvoiceAmt>


  </invoice>


  <invoice>


    <CustomerName>xyz</CustomerName>


    <InvoiceNum>981</InvoiceNum>


    <InvoiceDate>2000-12-13</InvoiceDate>


    <InvoiceCurrency>CU</InvoiceCurrency>


    <InvoiceAmt>675.98</InvoiceAmt>


  </invoice>


  <invoice>


    <CustomerName>xyz</CustomerName>


    <InvoiceNum>998</InvoiceNum>


    <InvoiceDate>2000-12-25</InvoiceDate>


    <InvoiceCurrency>CU</InvoiceCurrency>


    <InvoiceAmt>973.87</InvoiceAmt>


  </invoice>


</table>

Examining the resulting XML file, each <invoice> element has 5 child elements each representing a piece of data relating to the invoice, with each of those child elements storing the data as its value. If the focus of this table/report is on the invoice amount <invoiceAmt>, then it might be better to have the invoice amount information as the only value, and everything else might be better represented as an attribute. Attributes usually provide additional contextual information about the element and its value, we may call those attributes aspects or even dimensions. So let’s try to rewrite the XML in a different way to reflect this:

# Re-write the XML file with attributes

# create root element for the new XML
xml_root_2 <- xml2::xml_new_root('table')

# define children with attributes
for(r in asplit(tbl_1,1)) {
  nd <- xml2::xml_add_child(xml_root_2, 'invoice', r[[length(r)]])
  for(r_n in names(r)){
    xml2::xml_attrs(nd) <- r[-length(r)]
  }
}

# Write the XML document to file
xml_out_tbl_2 <- here::here('xml_files','xml_out_2.xml')
invisible(xml2::write_xml(xml_root_2, xml_out_tbl_2))

The resulting New XML file looks like this:

<?xml version="1.0" encoding="UTF-8"?>


<table>


  <invoice CustomerName="abc" InvoiceNum="264" InvoiceDate="2000-01-05" InvoiceCurrency="CU">650.60</invoice>


  <invoice CustomerName="abc" InvoiceNum="396" InvoiceDate="2000-01-24" InvoiceCurrency="CU">441.60</invoice>


  <invoice CustomerName="abc" InvoiceNum="455" InvoiceDate="2000-04-18" InvoiceCurrency="CU">492.19</invoice>


  <invoice CustomerName="abc" InvoiceNum="509" InvoiceDate="2000-07-30" InvoiceCurrency="CU">133.69</invoice>


  <invoice CustomerName="mno" InvoiceNum="631" InvoiceDate="2000-09-15" InvoiceCurrency="CU">976.19</invoice>


  <invoice CustomerName="mno" InvoiceNum="700" InvoiceDate="2000-10-09" InvoiceCurrency="CU">488.58</invoice>


  <invoice CustomerName="mno" InvoiceNum="721" InvoiceDate="2000-10-24" InvoiceCurrency="CU">961.82</invoice>


  <invoice CustomerName="abc" InvoiceNum="978" InvoiceDate="2000-11-09" InvoiceCurrency="CU">898.98</invoice>


  <invoice CustomerName="xyz" InvoiceNum="981" InvoiceDate="2000-12-13" InvoiceCurrency="CU">675.98</invoice>


  <invoice CustomerName="xyz" InvoiceNum="998" InvoiceDate="2000-12-25" InvoiceCurrency="CU">973.87</invoice>


</table>

Now that we have modeled our information in an acceptable form, we can try to re-construct the table from the XML, here I am using R script xml2 library to do that, but it can be done on any system using any language or software capable of parsing XML files:

# Read XML file
xml_tbl <- xml2::read_xml(xml_out_tbl_2)

# find all invoice elements
invoices <- xml2::xml_find_all(xml_tbl, './/invoice')
values <- xml2::xml_find_all(xml_tbl, './/invoice/text()') %>% xml2::as_list() %>% unlist()

# extract invoice attributes and values from all elements and convert to a dataframe
xml_to_tbl <- xml2::xml_attrs(invoices) %>% bind_rows() %>% 
  mutate(InvoiceAmt= as.double(values)) %>% as.data.frame()
# Correct data types
xml_to_tbl$InvoiceNum <- as.integer(xml_to_tbl$InvoiceNum)
xml_to_tbl$InvoiceDate <- as.Date(xml_to_tbl$InvoiceDate)
head(xml_to_tbl)
# Compare result of conversion to original table
paste("Matches Original: ", all_equal(xml_to_tbl, tbl_1)) # Should return TRUE
[1] "Matches Original:  TRUE"

3.6.3 XML Schema, Namespaces and Validation

As mentioned, XML is used to transport information between systems, and now that we have an XML document is created in the previous section, the next step will be to send it to the destination system. But an important question arises, how do we make sure that the destination/receiving system is able to handle and verify the information in our document correctly? For example, the root element in the example document is called table, what should be expected to be included in a table element? Is it a table of invoices, or is it a table a piece of furniture?

To address the above questions, XML has mechanisms whereby elements in an XML document can be described and verified, these is mechanisms mainly depend on schema, namespaces and types.

Schema Is a component of XML (W3C recommendation) used to describe and validate elements in an XML document. Schema can be described as the blueprint of vocabulary used, what and how data is stored in an XML file, and what are the data types of stored data. there are different schema languages such as Document Type Definitions (DTDs), Relax-NG, Schematron and W3C XSD (XML Schema Definitions). The focus will be on XSD as this is the Schema language used in XBRL. XSD being written in XML, it has one root element that contains all the declarations, the root element is <schema> and it is defined as follows:

Namespaces Is a component of XML (W3C recommendation) used for providing uniquely named elements and attributes in an XML document. XML document may contain elements from multiple vocabularies (schema), namespaces help in uniquely identifying elements from different vocabularies having identical names. A namespace takes the form of a URI, for example http://mynamespace.com/1/1. A namespace prefix can be declared in an XML document to refer to specific namespace using @xmlns attribute, for example xmlns:myns=http://mynamespace.com/1/1.

Types and Derivation in xsd
Elements declared in an xsd schema are based on XML built-in data types, or types that are derived from these built-in types. Types in xsd determines the value, content and composition of elements, for example, an element that holds a date value may make use of the built-in type date and may be typed by setting the type attribute type=date. W3C specifications for data types is available here and here. A depiction of built-in datatypes hierarchy from W3C specifications:

Given that XML instance can have one and only one root element, this element will inevitably include other elements that have more complicated content than just holding a value of a certain type, and built-in types will not be enough to type these elements. The answer to that is in the X of XML which stands for eXtensible, xsd provides capabilities for creating new types derived from built-in types or other types that are already derived from built-in types. A Summary of type derivation in XSD is as follows:

A useful resource on the topic of XSD data types and derivation is available here.

Following with the invoices table example, a schema was created for this report (using any schema creation software), the schema insures the following:

  • Namespace http://myproject.com/test2/1 was given to refer to the vocabulary of the schema
  • The root element is called table and contains one or more invoice element
  • Each invoice element is required to have a specific set of attributes as follows:
    • @InvoiceNum of data type positive integer
    • @InvoiceDate of data type date
    • @InvoiceCurrency a string that can be either “CU” or “CX”
    • @CustomerName of data type string
    • Finally invoice value must be a positive number or 0

Schema file is as follows:

<?xml version="1.0" encoding="UTF-8"?>


<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"


    xmlns:inv="http://myproject.com/test2/1"


    targetNamespace="http://myproject.com/test2/1"


    elementFormDefault="qualified"


    >


    


    <xs:simpleType name="currType">


        <xs:annotation>


            <xs:documentation>Currency type selection either "CU" or "CX"


            </xs:documentation>


        </xs:annotation>


        <xs:restriction base="xs:string">


            <xs:enumeration value="CU" /> 


            <xs:enumeration value="CX" />


        </xs:restriction>


    </xs:simpleType>


    <xs:attributeGroup name="invoiceGrp">


        <xs:annotation>


            <xs:documentation>Type defining the invoice required information


            </xs:documentation>


        </xs:annotation>


        <xs:attribute name="InvoiceNum" type="xs:unsignedShort"


            use="required" />


        <xs:attribute name="InvoiceDate" type="xs:date"


            use="required" />


        <xs:attribute name="InvoiceCurrency" type="inv:currType"


            use="required" />


        <xs:attribute name="CustomerName" type="xs:string"


            use="required" />


    </xs:attributeGroup>


    <xs:simpleType name="positive_decimalType">


        <xs:annotation>


            <xs:documentation>Restriction on invoice amount to be always a


                positive number.</xs:documentation>


        </xs:annotation>


        <xs:restriction base="xs:decimal">


            <xs:minInclusive value="0" />


        </xs:restriction>


    </xs:simpleType>


    <xs:complexType name="invoiceType">


        <xs:annotation>


            <xs:documentation>Invoice type based using declared positive decimal


                type and invoice attributes group.</xs:documentation>


        </xs:annotation>


        <xs:simpleContent>


            <xs:extension base="inv:positive_decimalType">


                <xs:attributeGroup ref="inv:invoiceGrp" />


            </xs:extension>


        </xs:simpleContent>


    </xs:complexType>


    <xs:element name="table">


        <xs:annotation>


            <xs:documentation>Defines root node using declared invoiceType.


            </xs:documentation>


        </xs:annotation>


        <xs:complexType>


            <xs:sequence>


                <xs:element maxOccurs="unbounded" name="invoice"


                    type="inv:invoiceType" minOccurs="1" />


            </xs:sequence>


        </xs:complexType>


    </xs:element>


</xs:schema>

Now we need to change our XML file to reference the schema, that is done using the @xmlns attribute and giving it a namespace prefix of ‘inv’, and providing the location of the schema file using @xs:schemaLocation attribute, note that the later attribute is from xs=http://www.w3.org/2001/XMLSchema-instance namespace. The new file with the schema reference is named xml_out_2_schema.xml and and the relevant part of it looks as follows:

<inv:table xmlns:inv="http://myproject.com/test2/1" 


    xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" 


    xs:schemaLocation="http://myproject.com/test2/1 example_2_schema2.xsd">

Validation with no errors
Before processing the XML file, the receiving computer will always validate the XML file against the referenced schema, we can do that here using R script xml2::xml_validate() function as follows:

# Read XML instance and schema
inst <- xml2::read_xml(here::here("xml_files","xml_out_2_schema.xml"))
schema <- xml2::read_xml(here::here("xml_files","example_2_schema2.xsd"))

# Validate XML instance against the schema
xml2::xml_validate(inst,schema)
[1] TRUE
attr(,"errors")
character(0)

Validating the first file returns TRUE with 0 errors, meaning that the file is valid according to the schema.

Validation with Errors
Now let’s change the file and test if the validation will detect the errors. We create a new file called xml_out_2_schema_errors.xml, and we change it to be as follows:

  1. For the first invoice remove @CustomerName attribute -> test missing attributes are detected
  2. For the second invoice change @InvoiceNum value to string ix-> test inconsistent attribute datatype is detected
  3. For the third invoice change @InvoiceCurrency value to XZ -> test only valid currency choices are allowed
  4. in the fourth invoice change the value from 133.69 to -133.69 -> test if only positive invoice amount values are allowed.

Then we run the validation again on the modified file, we should get an error this time:

# Read XML instance and schema",
inst_err <- xml2::read_xml(here::here("xml_files","xml_out_2_schema_errors.xml"))
schema <- xml2::read_xml(here::here("xml_files","example_2_schema2.xsd"))

# Validate XML instance against the schema
xml2::xml_validate(inst_err,schema)
[1] FALSE
attr(,"errors")
[1] "Element '{http://myproject.com/test2/1}invoice': The attribute 'CustomerName' is required but missing."                                                              
[2] "Element '{http://myproject.com/test2/1}invoice', attribute 'InvoiceNum': 'ix' is not a valid value of the atomic type 'xs:unsignedShort'."                           
[3] "Element '{http://myproject.com/test2/1}invoice', attribute 'InvoiceCurrency': [facet 'enumeration'] The value 'XZ' is not an element of the set {'CU', 'CX'}."       
[4] "Element '{http://myproject.com/test2/1}invoice', attribute 'InvoiceCurrency': 'XZ' is not a valid value of the atomic type '{http://myproject.com/test2/1}currType'."
[5] "Element '{http://myproject.com/test2/1}invoice': [facet 'minInclusive'] The value '-133.69' is less than the minimum value allowed ('0')."                           
[6] "Element '{http://myproject.com/test2/1}invoice': '-133.69' is not a valid value of the atomic type '{http://myproject.com/test2/1}positive_decimalType'."            

As shown above, a simple XML validator (xml2) detected all the errors and reported them.